package com.lovezy.platform.core.valid;

import com.lovezy.platform.core.exception.BaseRuntimeException;
import com.lovezy.platform.core.exception.DefaultErrorCode;
import com.lovezy.platform.core.exception.ServiceException;
import com.lovezy.platform.core.exception.ValidationException;
import com.lovezy.platform.core.valid.annotation.Alias;
import com.lovezy.platform.core.valid.annotation.NotTrim;
import com.lovezy.platform.core.valid.annotation.Required;
import com.lovezy.platform.core.valid.annotation.ValidatorProvider;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jetbrains.annotations.NotNull;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;

import static com.lovezy.platform.core.utils.ObjectUtil.copy;

/**
 *
 * 校验器 通过注解的方式实现校验
 * 
 */
public class ValidatorUtil {
	private static final Log log = LogFactory.getLog(ValidatorUtil.class);

	private static final Map<String, Validator> pool = new HashMap<>();


	/**
	 *
	 * 校验source，并把属性copy到target
	 *
	 */
	public static void validateAndCopy(Object source, Object target) {
		if (target == null)
			throw new ValidationException(DefaultErrorCode.VALID_ERROR, "被拷贝目标对象为null");
		// 校验对象
		validate(source);
		// copy属性
		copy(source, target);
	}


	public static void validate(@NotNull Object o, @NotNull Class<? extends Annotation> annotationClass) {
		Annotation annotation = o.getClass().getAnnotation(annotationClass);
		if (annotation == null) {
			throw new NullPointerException(annotationClass + "不存在");
		}
		ValidatorProvider provider = annotation.getClass().getAnnotation(ValidatorProvider.class);
		if (provider == null) {
			throw new NullPointerException(annotation + "校验器提供者为空");
		}
		Validator validator = getValidator(provider.value());
		validator.validate(o, annotation);
	}

	private static void doValidate(Object target, boolean continueIfNull) {
		// 被校验的对象为空，抛异常
		if (target == null) {
			throw new ValidationException(DefaultErrorCode.VALID_ERROR, "校验对象不存在");
		}
		// 取定义的全部属性
		Field[] fields = target.getClass().getDeclaredFields();
		if (isEmpty(fields)) {
			return;
		}

		for (Field field : fields) {
			singleFieldValidate(field,target,continueIfNull);
		}

		if (target instanceof Check) {
			((Check) target).check();
		}

	}

	private static void singleFieldValidate(Field field, Object target,boolean continueIfNull) {
		// 属性值
		Object value = null;
		try {
			boolean original = field.isAccessible();
			field.setAccessible(true);
			value = field.get(target);
			// 如果值不为空，且是String类型
			if (value == null) {
				Required required = field.getAnnotation(Required.class);
				if (required != null) {
					throw new ValidationException(required.errorCode(), required.errorMsg());
				} else {
					if (log.isDebugEnabled()) {
						log.debug(field.getName() + " is null");
						return;
					}
				}
			} else {
				if (value instanceof String) {
					boolean ch = Modifier.isFinal(field.getModifiers())
							|| Modifier.isStatic(field.getModifiers());
					if (!(ch || field.getAnnotation(NotTrim.class) != null)) {
						// 否则默认都去前后空格
						value = value.toString().trim();
						field.set(target, value);
					}
				}
			}
			field.setAccessible(original);
		} catch (BaseRuntimeException e) {
			throw e;
		} catch (Exception e) {
			log.error("检验出错", e);
			throw new ServiceException("检验表单出错");
		}

		checkFieldValue(field, value);
	}


	/**
	 * 校验对象的属性是否符合注解中的规则
	 * 
	 * @param target
	 *            被校验的对象
	 */
	public static void validate(Object target) {
		doValidate(target, false);
	}

	/**
	 * 校验对象的属性是否符合注解中的规则
	 * 并且忽略Required
	 *
	 * @param target
	 *            被校验的对象
	 */
	public static void validateNotNull(Object target) {
		doValidate(target,true);
	}


	/**
	 * 校验指定别名的对象属性是否符合注解中的规则
	 * 
	 * @param target
	 *            被校验的对象
	 */
	public static void validate(Object target, String alias) {
		// 被校验的对象为空，抛异常
		if (target == null) {
			throw new ValidationException(DefaultErrorCode.VALID_ERROR, "校验对象不存在");
		}
		// 取定义的全部属性
		Field[] fields = target.getClass().getDeclaredFields();
		if (isEmpty(fields)) {
			return;
		}

		for (Field field : fields) {
			Alias aliasAnnotation = field.getAnnotation(Alias.class);
			if(null != aliasAnnotation && containsAlias(aliasAnnotation, alias)) {
				singleFieldValidate(field, target, false);
			}
		}
	}

	/**
	 * 校验指定别名的对象属性是否符合注解中的规则
	 * @param target 被校验的对象
	 * @param alias 需要校验的别名参数
	 */
	public static void validateAlias(Object target, String... alias){
		for (String alia : alias) {
			validate(target, alia);
		}
	}
	

	/**
	 * 校验属性字段的值
	 * 
	 * @param field 字段
	 * @param fieldValue 字段的值
	 * 
	 */
	private static void checkFieldValue(Field field, Object fieldValue) {
		Annotation[] annotations = field.getDeclaredAnnotations();
		if (isEmpty(annotations)) {
			return;
		}
		for (Annotation annotation : annotations) {
			if (annotation instanceof Required || annotation instanceof NotTrim || annotation instanceof Alias)
				continue;

			ValidatorProvider provider = annotation.annotationType()
					.getAnnotation(ValidatorProvider.class);
			if (provider == null) {
				if (log.isDebugEnabled())
					log.warn(annotation.annotationType() + "对应的"
							+ ValidatorProvider.class + "不存在");
			} else {
				getValidator(provider.value()).validate(fieldValue, annotation);
			}
		}
	}

	/**
	 * 根据校验器的类类型,创建对应的实例
	 * 
	 * @param claz 校验器类
	 * @return 校验器实例
	 *
	 */
	private static Validator getValidator(Class<? extends Validator> claz) {
		Validator val = pool.get(claz.getSimpleName());
		if (val == null) {
			try {
				val = claz.newInstance();
				pool.put(claz.getName(), val);
			} catch (Exception e) {
				log.error(e.getMessage(), e);
			}
		}

		return val;
	}

	private static boolean isEmpty(Object[] arr) {
		return arr == null || arr.length == 0;
	}
	
	private static boolean containsAlias(Alias alias, String aliasValue){
		String[] values = alias.value();
		for(String value: values){
			if(value.equals(aliasValue))
				return true;
		}
		return false;
	}
}
